package com.partition.mysql.handle;



import com.partition.mysql.bean.PartitionInfo;
import com.partition.mysql.bean.PartitionItem;
import com.partition.mysql.biz.PartitionManager;
import com.partition.mysql.interfaze.PartitionHandler;
import com.partition.mysql.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 按天分区实现
 *
 * @author hexinglin
 * @created 2022-04-08 16:36
 **/
@Component
public class PartitionByDayHandler implements PartitionHandler {
    private static final Logger logger = LoggerFactory.getLogger(PartitionByDayHandler.class);

    @Autowired
    private PartitionManager partitionManager;

    /**
     * 对表分区
     *
     * @param item
     * @return
     */
    @Override
    public void partition(PartitionItem item) {
        logger.info("---------表：{}分区按：{}处理----------",item.getTableName(),item.getRangeStrategy());
        List<PartitionInfo> partitionInfos = partitionManager.queryPartitionInfos(item.getTableName());
        if (CollectionUtils.isEmpty(partitionInfos)){
            //该表没有建立任何分区，开始建立分区
            initPart(item);
        }else  if (StringUtils.isEmpty(partitionInfos.get(0).getPartitionName())){
            //如果第一个分区名为空则新建分区,表名没有建立任何分区，开始建立分区
            initPart(item);
        }else {
            //判断最后一个分区是否满足设置的预先数量，小于预先创建数量则增加分区
            addPart(partitionInfos,item);
        }
    }

    /**
     * 定时任务处理表分区
     *
     * @param item
     * @return
     */
    @Override
    public void partitionJob(PartitionItem item) {
        List<PartitionInfo> partitionInfos = partitionManager.queryPartitionInfos(item.getTableName());
        //去除查询为空的数据
        List<PartitionInfo> partitionNames = partitionInfos.stream().filter(m->!StringUtils.isEmpty(m.getPartitionName())).collect(Collectors.toList());
        //追加分区
        addPart(partitionNames,item);
        //删除分区
        deletePart(partitionNames,item);

    }


    /*
    *初始化分区
    */
    private void initPart(PartitionItem item){
        //1.对需要分区的字段增加联合索引
        partitionManager.alertPrimaryKey(item.getTableName(),item.getRangeColumnName());
        //2.初始化分区
        partitionManager.initPartition(item);
    }

    /*
     *后续追加分区
     */
    private void addPart(List<PartitionInfo> partitionInfos,PartitionItem item){

        //最新分区的时间戳
        Long lastTime = partitionInfos.get(0).getPartitionDescription();
        Long currentTime = DateUtils.getDayEnd(0);
        //计算天数数量差
        int diffLastDays = DateUtils.differentDaysByMillisecond(lastTime,currentTime);
        if (diffLastDays<item.getPreNums()){
            //添加分区
            Map<String,Long> partMap = DateUtils.getDateMap(item.getRangeStrategy(),diffLastDays+1,item.getPreNums());
            partitionManager.addPartitionByMap(item.getTableName(),partMap);
        }

    }

    /*
     *后续清理分区
     */
    private void deletePart(List<PartitionInfo> partitionInfos,PartitionItem item){

        PartitionInfo firstInfo = partitionInfos.get(partitionInfos.size()-1);
        Long currentTime = DateUtils.getDayEnd(0);
        Long firstTime = firstInfo.getPartitionDescription();
        //计算天数数量差
        int diffFirstDays = DateUtils.differentDaysByMillisecond(currentTime,firstTime);

        if (diffFirstDays>item.getRetainNumsOnClear()){
            //如果分区数大于设定的则开始删除分区
            //1.获取需要删除的时间节点
            Long deleteTime = DateUtils.getDayEnd(-item.getRetainNumsOnClear());
            //2.获取需要删除的分区名称
            List<String> partitionNameList = partitionInfos.stream().filter(p -> p.getPartitionDescription() < deleteTime)
                    .map(PartitionInfo::getPartitionName).collect(Collectors.toList());
            partitionManager.deletePartition(item.getTableName(),partitionNameList);
        }
    }
}
